Now can get all configs
authorYehuda Katz <wycats@gmail.com>
Mon, 7 Apr 2014 03:31:50 +0000 (20:31 -0700)
committerYehuda Katz <wycats@gmail.com>
Mon, 7 Apr 2014 03:31:50 +0000 (20:31 -0700)
src/bin/cargo.rs
src/cargo/util/config.rs
src/cargo/util/important_paths.rs

index bfc3b1e3218581d2dc10977ad663eecb9543112c..36c620cc772ef4309746b948754cc2c672a82de8 100644 (file)
@@ -5,9 +5,9 @@ extern crate serialize;
 extern crate collections;
 
 use hammer::{FlagConfig,FlagConfiguration};
-use std::{os,io};
-use serialize::{Decodable,Encodable,json};
-use cargo::{CargoResult,ToCargoError,NoFlags,execute_main_without_stdin,process_executed,handle_error};
+use std::os;
+use serialize::Encodable;
+use cargo::{CargoResult,ToCargoError,NoFlags,execute_main_without_stdin,handle_error};
 use cargo::util::important_paths::find_project;
 use cargo::util::config;
 
@@ -20,13 +20,19 @@ struct ProjectLocation {
     root: ~str
 }
 
+/**
+  The top-level `cargo` command handles configuration and project location
+  because they are fundamental (and intertwined). Other commands can rely
+  on this top-level information.
+*/
 fn execute() {
-    let (cmd, args) = match process(os::args()) {
+    let (cmd, _) = match process(os::args()) {
         Ok((cmd, args)) => (cmd, args),
         Err(err) => return handle_error(err)
     };
 
-    if cmd == ~"config" { execute_main_without_stdin(config) }
+    if cmd == ~"config-for-key" { execute_main_without_stdin(config_for_key) }
+    else if cmd == ~"config-list" { execute_main_without_stdin(config_list) }
     else if cmd == ~"locate-project" { execute_main_without_stdin(locate_project) }
 }
 
@@ -38,25 +44,24 @@ fn process(mut args: ~[~str]) -> CargoResult<(~str, ~[~str])> {
     Ok((head, tail))
 }
 
+#[deriving(Encodable)]
+struct ConfigOut {
+    values: collections::HashMap<~str, config::ConfigValue>
+}
+
 #[deriving(Decodable)]
-struct ConfigFlags {
+struct ConfigForKeyFlags {
     key: ~str,
-    value: Option<~str>,
     human: bool
 }
 
-impl FlagConfig for ConfigFlags {
-    fn config(_: Option<ConfigFlags>, c: FlagConfiguration) -> FlagConfiguration {
-        c.short("human", 'h')
+impl FlagConfig for ConfigForKeyFlags {
+    fn config(_: Option<ConfigForKeyFlags>, config: FlagConfiguration) -> FlagConfiguration {
+        config.short("human", 'h')
     }
 }
 
-#[deriving(Encodable)]
-struct ConfigOut {
-    values: collections::HashMap<~str, config::ConfigValue>
-}
-
-fn config(args: ConfigFlags) -> CargoResult<Option<ConfigOut>> {
+fn config_for_key(args: ConfigForKeyFlags) -> CargoResult<Option<ConfigOut>> {
     let value = try!(config::get_config(os::getcwd(), args.key.as_slice()));
 
     if args.human {
@@ -69,7 +74,31 @@ fn config(args: ConfigFlags) -> CargoResult<Option<ConfigOut>> {
     }
 }
 
-fn locate_project(args: NoFlags) -> CargoResult<Option<ProjectLocation>> {
+#[deriving(Decodable)]
+struct ConfigListFlags {
+    human: bool
+}
+
+impl FlagConfig for ConfigListFlags {
+    fn config(_: Option<ConfigListFlags>, config: FlagConfiguration) -> FlagConfiguration {
+        config.short("human", 'h')
+    }
+}
+
+fn config_list(args: ConfigListFlags) -> CargoResult<Option<ConfigOut>> {
+    let configs = try!(config::all_configs(os::getcwd()));
+
+    if args.human {
+        for (key, value) in configs.iter() {
+            println!("{} = {}", key, value);
+        }
+        Ok(None)
+    } else {
+        Ok(Some(ConfigOut { values: configs }))
+    }
+}
+
+fn locate_project(_: NoFlags) -> CargoResult<Option<ProjectLocation>> {
     let root = try!(find_project(os::getcwd(), ~"Cargo.toml"));
     let string = try!(root.as_str().to_cargo_error(format!("Your project path contains characters not representable in Unicode: {}", os::getcwd().display()), 1));
     Ok(Some(ProjectLocation { root: string.to_owned() }))
index 087a7b3a74aaacc3f415e15e43fae1de7b87a66e..9f579fb7a735b33a78dd7ab4e858f76998b2b97f 100644 (file)
@@ -1,15 +1,16 @@
+extern crate collections;
 extern crate toml;
 
-use super::super::{CargoResult,CargoError,ToCargoError};
+use super::super::{CargoResult,ToCargoError};
 use std::{io,fmt};
 
-#[deriving(Eq,Clone,Encodable,Decodable)]
+#[deriving(Eq,TotalEq,Clone,Encodable,Decodable)]
 pub enum Location {
     Project,
     Global
 }
 
-#[deriving(Eq,Clone,Encodable,Decodable)]
+#[deriving(Eq,TotalEq,Clone,Encodable,Decodable)]
 pub struct ConfigValue {
     value: ~str,
     path: ~str
@@ -22,14 +23,29 @@ impl fmt::Show for ConfigValue {
 }
 
 pub fn get_config(pwd: Path, key: &str) -> CargoResult<ConfigValue> {
-    walk_tree(&pwd, |file| extract_config(file, key)).to_cargo_error(format!("Config key not found: {}", key), 1)
+    find_in_tree(&pwd, |file| extract_config(file, key)).to_cargo_error(format!("Config key not found: {}", key), 1)
 }
 
+pub fn all_configs(pwd: Path) -> CargoResult<collections::HashMap<~str, ConfigValue>> {
+    let mut map = collections::HashMap::new();
+
+    walk_tree(&pwd, |file| {
+        let _ = extract_all_configs(file).map(|configs| {
+            for (key, value) in configs.move_iter() {
+                map.find_or_insert(key, value);
+            }
+        });
+    });
+
+    Ok(map)
+}
+
+#[allow(unused_variable)]
 pub fn set_config(key: ~str, value: ~str, location: Location) -> CargoResult<()> {
     Ok(())
 }
 
-fn walk_tree<T>(pwd: &Path, walk: |io::fs::File| -> CargoResult<T>) -> Option<T> {
+fn find_in_tree<T>(pwd: &Path, walk: |io::fs::File| -> CargoResult<T>) -> Option<T> {
     let mut current = pwd.clone();
 
     loop {
@@ -49,6 +65,19 @@ fn walk_tree<T>(pwd: &Path, walk: |io::fs::File| -> CargoResult<T>) -> Option<T>
     None
 }
 
+fn walk_tree(pwd: &Path, walk: |io::fs::File| -> ()) {
+    let mut current = pwd.clone();
+
+    loop {
+        let possible = current.join(".cargo").join("config");
+        if possible.exists() {
+            let _ = io::fs::File::open(&possible).map(|file| walk(file));
+        }
+
+        if !current.pop() { break; }
+    }
+}
+
 fn extract_config(file: io::fs::File, key: &str) -> CargoResult<ConfigValue> {
     let path = try!(file.path().as_str().to_cargo_error(~"", 1)).to_owned();
     let mut buf = io::BufferedReader::new(file);
@@ -56,3 +85,21 @@ fn extract_config(file: io::fs::File, key: &str) -> CargoResult<ConfigValue> {
     let val = try!(try!(root.lookup(key).to_cargo_error(~"", 1)).get_str().to_cargo_error(~"", 1));
     Ok(ConfigValue{ value: val.to_owned(), path: path })
 }
+
+fn extract_all_configs(file: io::fs::File) -> CargoResult<collections::HashMap<~str, ConfigValue>> {
+    let mut map = collections::HashMap::new();
+
+    let path = try!(file.path().as_str().to_cargo_error(~"", 1)).to_owned();
+    let mut buf = io::BufferedReader::new(file);
+    let root = try!(toml::parse_from_buffer(&mut buf).to_cargo_error(~"", 1));
+    let table = try!(root.get_table().to_cargo_error(~"", 1));
+
+    for (key, value) in table.iter() {
+        match value {
+            &toml::String(ref val) => { map.insert(key.to_owned(), ConfigValue { value: val.to_owned(), path: path.clone() }); }
+            _ => ()
+        }
+    }
+
+    Ok(map)
+}
index 231aca6787a6100dcee6f478d8565aa66de85d0a..a428f825c65d73a1d898210077d315e42868075d 100644 (file)
@@ -1,4 +1,3 @@
-use std::os;
 use super::super::{CargoResult,CargoError};
 
 pub fn find_project(pwd: Path, file: ~str) -> CargoResult<Path> {